package cn.iocoder.yudao.module.scrm.controller.admin.schedules;

import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.scrm.controller.admin.customer.CustomerController;
import cn.iocoder.yudao.module.scrm.controller.admin.customer.vo.CustomerRespVO;
import cn.iocoder.yudao.module.scrm.controller.admin.schedules.vo.*;
import cn.iocoder.yudao.module.scrm.dal.dataobject.customer.CustomerDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.product.CrmProductDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.schedules.SchedulesDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.schedulesteacher.SchedulesTeacherDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.teacher.TeacherDO;
import cn.iocoder.yudao.module.scrm.enums.schedules.ScrmSchedulesStatusEnum;
import cn.iocoder.yudao.module.scrm.service.product.CrmProductService;
import cn.iocoder.yudao.module.scrm.service.schedules.SchedulesCustomerService;
import cn.iocoder.yudao.module.scrm.service.schedules.SchedulesService;
import cn.iocoder.yudao.module.scrm.service.schedules.SchedulesTeacherService;
import cn.iocoder.yudao.module.scrm.service.teacher.TeacherService;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;

@Tag(name = "管理后台 - 排期")
@RestController
@RequestMapping("/scrm/schedules")
@Validated
public class SchedulesController {

    @Resource
    private SchedulesService schedulesService;

    @Resource
    private SchedulesCustomerService schedulesCustomerService;

    @Resource
    private SchedulesTeacherService schedulesTeacherService;

    @Resource
    private TeacherService teacherService;

    @Resource
    private CustomerController customerController;

    @Resource
    private CrmProductService crmProductService;

    @Resource
    private AdminUserApi adminUserApi;

    @Resource
    private PermissionApi permissionApi;

    @Resource
    private DeptApi deptApi;

    @PostMapping("/create")
    @Operation(summary = "创建排期")
    @PreAuthorize("@ss.hasPermission('scrm:schedules:create')")
    public CommonResult<Long> createSchedules(@Valid @RequestBody SchedulesSaveReqVO createReqVO) {
        return success(schedulesService.createSchedules(createReqVO));
    }

    @PutMapping("/update")
    @Operation(summary = "更新排期")
    @PreAuthorize("@ss.hasPermission('scrm:schedules:update')")
    public CommonResult<Boolean> updateSchedules(@Valid @RequestBody SchedulesSaveReqVO updateReqVO) {
        schedulesService.updateSchedules(updateReqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除排期")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('scrm:schedules:delete')")
    public CommonResult<Boolean> deleteSchedules(@RequestParam("id") Long id) {
        schedulesService.deleteSchedules(id);
        return success(true);
    }

    @GetMapping("/get")
    @Operation(summary = "获得排期")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('scrm:schedules:query')")
    public CommonResult<SchedulesRespVO> getSchedules(@RequestParam("id") Long id) {
        SchedulesDO schedules = schedulesService.getSchedules(id);
        List<SchedulesTeacherDO> teacherDOS = schedulesTeacherService.getTeachersBySchedulesIds(Collections.singletonList(id));
        List<Long> teacherIds = teacherDOS.stream().map(SchedulesTeacherDO::getTeacherId).collect(Collectors.toList());
        Map<Long, TeacherDO> map = teacherService.getTeacherMap(teacherIds);

        List<PersonInfo> personInfos = teacherDOS.stream()
                .map(teacher -> {
                    PersonInfo personInfo = new PersonInfo();
                    personInfo.setId(teacher.getTeacherId());
                    personInfo.setName(teacher.getTeacherName());
                    // 可能的空指针处理
                    TeacherDO teacherDO = map.get(teacher.getTeacherId());
                    if (teacherDO != null) {
                        personInfo.setAvatar(teacherDO.getAvatar());
                    }
                    return personInfo;
                })
                .collect(Collectors.toList());

        SchedulesRespVO respVO = BeanUtils.toBean(schedules, SchedulesRespVO.class);
        Long remainingSeats = schedulesCustomerService.getCustomerCountBySchedulesId(respVO.getId());
        Map<Long, CrmProductDO> productMap = crmProductService.getProductMap(Collections.singletonList(respVO.getProductId()));
        respVO.setRemainingSeats(respVO.getSeatCount() - remainingSeats);
        respVO.setPersonInfoList(personInfos);
        respVO.setProductName(ObjectUtils.isEmpty(productMap.get(respVO.getProductId())) ? "" : productMap.get(respVO.getProductId()).getName());

        // 设置创建者名称、部门
        AdminUserRespDTO checkedData = adminUserApi.getUserNotCheckDataPermission(respVO.getCreator()).getCheckedData();
        Optional.ofNullable(checkedData)
                .ifPresent(data -> {
                    respVO.setCreatorName(data.getNickname());
                    respVO.setCreatorDept(Optional.ofNullable(data.getDeptId())
                            .map(deptApi::getDeptNotCheckDataPermission)
                            .map(CommonResult::getCheckedData)
                            .map(DeptRespDTO::getName)
                            .orElse(""));
                });
        return success(respVO);
    }

    @GetMapping("/page")
    @Operation(summary = "获得排期分页")
//    @PreAuthorize("@ss.hasPermission('scrm:schedules:query')")
    @PermitAll
    public CommonResult<PageResult<SchedulesRespVO>> getSchedulesPage(@Valid SchedulesPageReqVO pageReqVO) {

        // 查询课程分页列表
        PageResult<SchedulesDO> pageResult = schedulesService.getSchedulesPage(pageReqVO);
        // 提取课程ID列表
        List<Long> schedulesIds = pageResult.getList().stream().map(SchedulesDO::getId).collect(Collectors.toList());
        // 根据课程ID批量查询教师信息
        List<SchedulesTeacherDO> teacherDOS = schedulesTeacherService.getTeachersBySchedulesIds(schedulesIds);
        // 根据教师ID列表批量查询教师详细信息，并转换为Map以便快速查询
        Map<Long, TeacherDO> teacherMap = teacherService.getTeacherMap(
                teacherDOS.stream().map(SchedulesTeacherDO::getTeacherId).distinct().collect(Collectors.toList())
        );
        // 根据产品ID查询产品信息，并转换为map
        Map<Long, CrmProductDO> productMap = crmProductService.getProductMap(
                pageResult.getList().stream().map(SchedulesDO::getProductId).distinct().collect(Collectors.toList())
        );

        // 将查询到的课程分页列表转换为响应对象
        PageResult<SchedulesRespVO> result = BeanUtils.toBean(pageResult, SchedulesRespVO.class);

        // 1.1 获取创建人、负责人列表
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMapNotCheckDataPermission(convertListByFlatMap(pageResult.getList(), contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()))));

        // 遍历课程列表，为每门课程设置教师信息
        result.getList().forEach(schedulesRespVO -> {
            // 根据课程ID过滤出对应的教师信息
            List<PersonInfo> personInfos = teacherDOS.stream()
                    .filter(teacher -> teacher.getSchedulesId().equals(schedulesRespVO.getId()))
                    .map(teacher -> {
                        // 创建并设置教师的个人信息对象
                        PersonInfo personInfo = new PersonInfo();
                        personInfo.setId(teacher.getTeacherId());
                        personInfo.setName(teacher.getTeacherName());
                        // 获取教师的头像信息，确保安全访问
                        TeacherDO teacherDO = teacherMap.get(teacher.getTeacherId());
                        if (teacherDO != null) {
                            personInfo.setAvatar(teacherDO.getAvatar());
                        }
                        return personInfo;
                    })
                    .collect(Collectors.toList());
            // 将教师信息列表设置到课程的响应对象中
            schedulesRespVO.setPersonInfoList(personInfos);
            Long remainingSeats = schedulesCustomerService.getCustomerCountBySchedulesId(schedulesRespVO.getId());
            schedulesRespVO.setRemainingSeats(schedulesRespVO.getSeatCount() - remainingSeats);
            schedulesRespVO.setProductName(ObjectUtils.isEmpty(productMap.get(schedulesRespVO.getProductId())) ? "" : productMap.get(schedulesRespVO.getProductId()).getName());

            // 2.1 设置创建人、负责人名称
            MapUtils.findAndThen(userMap, schedulesRespVO.getCreator(), user -> schedulesRespVO.setCreatorName(user.getNickname()));

        });

        // 返回成功响应，包含课程和教师信息
        return success(result);
    }

    @GetMapping("/export-excel")
    @Operation(summary = "导出排期 Excel")
    @PreAuthorize("@ss.hasPermission('scrm:schedules:export')")
    @OperateLog(type = EXPORT)
    public void exportSchedulesExcel(@Valid SchedulesPageReqVO pageReqVO,
                                     HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<SchedulesDO> list = schedulesService.getSchedulesPage(pageReqVO).getList();
        List<SchedulesRespVO> beanVo = BeanUtils.toBean(list, SchedulesRespVO.class);
        //设置状态值
        Map<Long, CrmProductDO> productMap = crmProductService.getProductMap(
                beanVo.stream().map(SchedulesRespVO::getProductId).distinct().collect(Collectors.toList())
        );

        // 1.1 获取创建人、负责人列表
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMapNotCheckDataPermission(convertListByFlatMap(list, contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()))));
        Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMapNotCheckDataPermission(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));

        for (SchedulesRespVO respVO : beanVo) {
            respVO.setStatusName(ScrmSchedulesStatusEnum.getDescriptionByCode(respVO.getStatus()));
            MapUtils.findAndThen(userMap, respVO.getCreator(), user -> respVO.setCreatorName(user.getNickname()));
            MapUtils.findAndThen(productMap, respVO.getProductId(), user -> respVO.setProductName(user.getName()));
            MapUtils.findAndThen(userMap, respVO.getCreator(), user -> {
                MapUtils.findAndThen(deptMap, user.getDeptId(), dept -> respVO.setCreatorDept(dept.getName()));
            });
        }
        // 导出 Excel
        ExcelUtils.write(response, "排期.xls", "数据", SchedulesRespVO.class,
                beanVo);
    }

    @PostMapping("/createCustomer")
    @Operation(summary = "创建排期客户")
    @PreAuthorize("@ss.hasPermission('scrm:schedules:create')")
    public CommonResult<Boolean> createSchedulesCustomer(@Valid @RequestBody SchedulesCustomerSaveReqVO createReqVO) {
        return success(schedulesCustomerService.createSchedulesCustomer(createReqVO));
    }

    @GetMapping("/getCustomer")
    @Operation(summary = "获取排期客户")
    @PermitAll
    public CommonResult<PageResult<CustomerRespVO>> getCustomer(@Valid SchedulesPageReqVO pageReqVO) {
        //不是超级管理员只能查询自己的
        Long loginUserId = getLoginUserId();
        if (loginUserId!=null && !permissionApi.roleIsSuperAdmin(loginUserId).getCheckedData()){
            pageReqVO.setCreator(Objects.requireNonNull(loginUserId).toString());
        }

        IPage<CustomerDO> page = schedulesService.getCustomerList(pageReqVO);
        return success(new PageResult<>(customerController.buildCustomerDetailList(page.getRecords()), page.getTotal()));
    }

}